﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.Serialization;

namespace Medicae_Toolkit
{
    /// <summary>
    /// Character is the storage class that contains all the information relevant to dealing with 
    /// PC characters.
    /// </summary>
    [Serializable()]
    public class Character : ISerializable
    {
        public enum location // Various targetable locations
        {
            Head = 0,
            Right_Arm,
            Left_Arm,
            Body,
            Right_Leg,
            Left_Leg,
            End
        }

        public string name;          // Character's Name
        public int toughness;        // Character's Toughness Characteristic
        public bool hardy;           // Whether or not Character has talent  that makes them always 'Lightly Wounded'
        public bool autosanguinate;  // Whether or not Character has talent  that makes them always 'Lightly Wounded'
        public int[] damage;         // Damage to each body location
        public int woundcap;         // Character's highest possible wounds
        public int wounds;           // Character's wounds

        /// <summary>
        /// All variables are set here so that the CharEditor simply has to
        /// replace the relevant ones, such as name, toughness, and wounds.
        /// </summary>
        public Character()
        {
            name = "";
            damage = new int[] { 0, 0, 0, 0, 0, 0 };
            toughness = -1;
            hardy = false;
            autosanguinate = false;
            woundcap = -1;
            wounds = -1;
        }

        /// <summary>
        /// Simple function for calculating the Toughness bonus of Character.
        /// </summary>
        public int ToughnessBonus
        {
            get
            {
                return Convert.ToInt32(Math.Floor((double)(toughness / 10)));
            }
        }
        
        /// <summary>
        /// Determines the status of the Character as determined by Dark Heresy rules
        /// </summary>
        public string DetermineStatus()
        {
            double TB = Math.Floor((double)(toughness / 10));
            if (wounds < -7)
            {
                return "Dead";
            }
            if (wounds < 0)
            {
                return (hardy || autosanguinate ? "Lightly Wounded" : "Critically Wounded");
            }
            else if (TB * 2 < (woundcap - wounds))
            {
                return (hardy || autosanguinate ? "Lightly Wounded" : "Heavily Wounded");
            }
            else if (woundcap > wounds)
            {
                return "Lightly Wounded";
            }
            else
            {
                return "Healthy";
            }
        }

        public Character(SerializationInfo info, StreamingContext ctxt)
        {
            this.name = (string)info.GetValue("Name", typeof(string));
            this.toughness = (int)info.GetValue("Toughness", typeof(int));
            this.hardy = (bool)info.GetValue("Hardy", typeof(bool));
            this.autosanguinate = (bool)info.GetValue("AutoSang", typeof(bool));
            this.damage = (int[])info.GetValue("Damage", typeof(int[]));
            this.woundcap = (int)info.GetValue("MaxWounds", typeof(int));
            this.wounds = (int)info.GetValue("Wounds", typeof(int));
        }

        public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
        {
            info.AddValue("Name", this.name);
            info.AddValue("Toughness", this.toughness);
            info.AddValue("Hardy", this.hardy);
            info.AddValue("AutoSang", this.autosanguinate);
            info.AddValue("Damage", this.damage);
            info.AddValue("MaxWounds", this.woundcap);
            info.AddValue("Wounds", this.wounds);
        }

        /// <summary>
        /// Controls what is displayed when an Array of Characater objects is displayed
        /// in a ListBox control.
        /// </summary>
        public override string ToString()
        {
            return name;
        }
    }

    /// <summary>
    /// Churigeon contains all the relavent data for a PC's Medicae as well as
    /// the function that determines degrees of success.
    /// </summary>
    [Serializable()]
    public class Churigeon : ISerializable
    {
        public string name;
        public int IntStat;
        public bool plusTen;
        public bool plusTwenty;
        public bool Talented;
        public bool MasterChur;

        /// <summary>
        /// All variables are set here so that the ChurigeonEditor simply has to
        /// replace the relevant ones, in this case "name" and "IntStat".
        /// </summary>
        public Churigeon()
        {
            name = "";
            IntStat = -1;
            plusTen = false;
            plusTwenty = false;
            Talented = false;
            MasterChur = false;
        }

        /// <summary>
        /// Simple function for calculating the Toughness bonus of Churigeon.
        /// </summary>
        public int IntellectBonus
        {
            get
            {
                return Convert.ToInt32(Math.Floor((double)(IntStat / 10)));
            }
        }

        /// <summary>
        /// Function for calculation the degrees of success on a Medicae roll.
        /// </summary>
        /// <param name="Roll">The pyhsical d100 roll.</param>
        /// <param name="Modifiers">Any conditional modifiers that affect the roll.</param>
        /// <returns> Integer that is the calculated amount that the roll exceeded the
        /// threshold by ten. </returns>
        public int GetDegrees(int Roll, int Modifiers)
        {
            int Cap = IntStat
                + (plusTen ? 10 : 0)
                + (plusTwenty ? 10 : 0)
                + (Talented ? 10 : 0)
                + (MasterChur ? 10 : 0)
                + Modifiers;

            Cap = (Cap > 99 ? 99 : Cap);

            int Result = Cap - Roll;
            Result = (int)Math.Floor((double)(Result / 10));

            return Result;
        }

        /// <summary>
        /// Controls what is displayed when an Array of Churigeon objects is displayed
        /// in a ListBox control.
        /// </summary>
        public override string ToString()
        {
            return name;
        }

        public Churigeon(SerializationInfo info, StreamingContext ctxt)
        {
            this.name = (string)info.GetValue("Name", typeof(string));
            this.IntStat = (int)info.GetValue("Intelligence", typeof(int));
            this.plusTen = (bool)info.GetValue("+10", typeof(bool));
            this.plusTwenty = (bool)info.GetValue("+20", typeof(bool));
            this.Talented = (bool)info.GetValue("Talented", typeof(bool));
            this.MasterChur = (bool)info.GetValue("MasterChur", typeof(bool));
        }

        public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
        {
            info.AddValue("Name", this.name);
            info.AddValue("Intelligence", this.IntStat);
            info.AddValue("+10", this.plusTen);
            info.AddValue("+20", this.plusTwenty);
            info.AddValue("Talented", this.Talented);
            info.AddValue("MasterChur", this.MasterChur);
        }
    }

    /// <summary>
    /// Custom Class built soley to contain the "Party", or List of Characters and
    /// Churigeons to be neatly serialized and deserialized.
    /// </summary>
    [Serializable()]
    public class SerialContainer : ISerializable
    {
        public List<Character> Serial1;
        public List<Churigeon> Serial2;
        public SerialContainer()
        {
            Serial1 = new List<Character>();
            Serial2 = new List<Churigeon>();
        }

        public SerialContainer(SerializationInfo info, StreamingContext ctxt)
        {
            this.Serial1 = (List<Character>)info.GetValue("Serial1", typeof(List<Character>));
            this.Serial2 = (List<Churigeon>)info.GetValue("Serial2", typeof(List<Churigeon>));
        }

        public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
        {
            info.AddValue("Serial1", this.Serial1);
            info.AddValue("Serial2", this.Serial2);
        }
    }
}
